using System.Drawing;
using System.IO;
using System.Threading;
using System.Windows.Forms;

namespace iDomainChecker
{
    internal class ValidateAgent
    {
        private DomainDictionary m_DomainDict;

        private WhoisServer[] m_SelectedItem;

        private DomainExtension[] m_DomainExts;

        private int m_ThreadCount;
        private int m_LivingThreadCount = 0;

        private Thread[] m_t;

        private ListBox m_lstAviable, m_lstUnaviable, m_lstTimeout, m_lstError;

        private ToolStripStatusLabel m_tlabTotalCount, m_tlabCheckedCount;
        private ToolStripProgressBar m_tspProgress;

        private Label m_labAvailableCount, m_labUnavailableCount, m_labTimeoutCount, m_labErrorCount;

        private int AvailableCount, UnabailableCount, TimeoutCount, ErrorCount, CurrentCount;

        public delegate void CheckFinishedHandle();

        public event CheckFinishedHandle OnCheckFinished;

        private Mutex Mut = new Mutex();

        private string m_ResultPath;

        private int m_RetryTimes;

        private TreeView m_tvThreads;


        public ValidateAgent(WhoisServer[] selectedWhoisServers, DomainExtension[] selectedDomainExtensions,
                             string domainDictionaryPath,
                             int threadCount, int retryTimes, string ResultPath, ListBox lstAviable, ListBox lstUnaviable, ListBox lstTimeout,
                             ListBox lstError, ToolStripStatusLabel tlabTotalCount,
                             ToolStripStatusLabel tlabCheckedCount, ToolStripProgressBar tspProgress,
                             Label labAvailableCount, Label labUnavailableCount, Label labTimeoutCount,
                             Label labErrorCount, TreeView tvThreads)
        {
            m_SelectedItem = selectedWhoisServers;
            m_DomainExts = selectedDomainExtensions;

            m_ThreadCount = threadCount;
            m_RetryTimes = retryTimes;

            m_ResultPath = ResultPath;

            m_DomainDict = new DomainDictionary(domainDictionaryPath);

            m_tlabTotalCount = tlabTotalCount;
            m_tlabCheckedCount = tlabCheckedCount;
            m_tspProgress = tspProgress;

            

            m_lstAviable = lstAviable;
            m_lstUnaviable = lstUnaviable;
            m_lstTimeout = lstTimeout;
            m_lstError = lstError;



            m_labAvailableCount = labAvailableCount;
            m_labUnavailableCount = labUnavailableCount;
            m_labTimeoutCount = labTimeoutCount;
            m_labErrorCount = labErrorCount;

            m_tvThreads = tvThreads;

            m_t = new Thread[threadCount];

            Thread GetDomainNameCount = new Thread(new ThreadStart(GetCount));
            GetDomainNameCount.Start();
        }

        private void GetCount()
        {
            Mut.WaitOne();
            m_tspProgress.Maximum = m_DomainDict.GetDomainNamesCount();
            m_tlabTotalCount.Text = m_tspProgress.Maximum.ToString();
            Mut.ReleaseMutex();
        }

        public void Start()
        {
            ThreadStart ts = new ThreadStart(CreateThread);
            for (int i = 0; i < m_ThreadCount; i++)
            {
                m_t[i] = new Thread(ts);
                m_LivingThreadCount++;
                m_t[i].Start();
                TreeNode tnode = new TreeNode("Thread " + i.ToString());
                tnode.BackColor = Color.FromArgb(192, 255, 192);
                m_tvThreads.Nodes.Add(tnode);
                Application.DoEvents();
            }
        }


        private void CreateThread()
        {
            Validate v = new Validate(m_LivingThreadCount, m_SelectedItem[0], m_DomainExts[0], m_DomainDict, m_RetryTimes);
            v.OnFoundValidDomainName += new Validate.FoundValidCheckResultHandler(OnFoundAvailableDomainName);
            v.OnFoundInvalidDomainName += new Validate.FoundValidCheckResultHandler(OnFoundUnavailableDomainName);
            v.OnFoundTimeOutDomainName += new Validate.FoundValidCheckResultHandler(OnFoundTimeoutDomainName);
            v.OnFoundOtherStatusDomainName += new Validate.FoundInvalidCheckResultHandler(OnFoundOtherStatusDomainName);
            v.OnCheckComplate += new Validate.CheckComplateHandler(OnCheckComplate);

            v.Start();
        }

        private void OnFoundAvailableDomainName(string DomainName, string DomainExtension)
        {
            WriteResult(m_lstAviable, DomainName + "." + DomainExtension);
            AvailableCount++;
            m_labAvailableCount.Text = AvailableCount.ToString();
        }

        private void OnFoundUnavailableDomainName(string DomainName, string DomainExtension)
        {
            WriteResult(m_lstUnaviable, DomainName + "." + DomainExtension);
            UnabailableCount++;
            m_labUnavailableCount.Text = UnabailableCount.ToString();
        }

        private void OnFoundTimeoutDomainName(string DomainName, string DomainExtension)
        {
            WriteResult(m_lstTimeout, DomainName + "." + DomainExtension);
            TimeoutCount++;
            m_labTimeoutCount.Text = TimeoutCount.ToString();
        }

        private void OnFoundOtherStatusDomainName(string DomainName, string DomainExtension, string ErrorMessage)
        {
            WriteResult(m_lstError, DomainName + "." + DomainExtension);
            ErrorCount++;
            m_labErrorCount.Text = ErrorCount.ToString();
            WriteErrorMessage(DomainName, DomainExtension, ErrorMessage);
        }

        /// <summary>
        /// Writes the error message.
        /// </summary>
        /// <param name="DomainName">Name of the domain.</param>
        /// <param name="DomainExtension">The domain extension.</param>
        /// <param name="ErrorMessage">The error message.</param>
        private void WriteErrorMessage(string DomainName,string DomainExtension,string ErrorMessage)
        {
            if(!Directory.Exists(m_ResultPath))
            {
                Directory.CreateDirectory(m_ResultPath);
            }
            
            StreamWriter sw = new StreamWriter(m_ResultPath + "\\" + DomainName + "." + DomainExtension + ".txt", false);
            sw.Write(ErrorMessage);
            sw.Close();
        }

        private void OnCheckComplate()
        {
            m_LivingThreadCount--;
            if (m_LivingThreadCount == 0)
            {
                m_DomainDict.Dispose();
                m_tvThreads.Nodes[m_LivingThreadCount].BackColor = Color.FromArgb(224, 224, 224);
                Application.DoEvents();
                OnCheckFinished();
            }
        }

        private void ChangeStatusBar()
        {
            Mut.WaitOne();
            CurrentCount++;
            m_tlabCheckedCount.Text = CurrentCount.ToString();

            if (m_tspProgress.Maximum >= CurrentCount)
            {
                m_tspProgress.Value = CurrentCount;
            }
            Mut.ReleaseMutex();
        }

        private void WriteResult(ListBox lst, string text)
        {
            Mut.WaitOne();
            lst.Items.Add(text);
            ChangeStatusBar();
            Mut.ReleaseMutex();
        }


        public void Stop()
        {
            for (int i = 0; i < m_ThreadCount; i++)
            {
                m_t[i].Abort();
                OnCheckComplate();
            }
        }

        public void Pause()
        {
            for (int i = 0; i < m_ThreadCount; i++)
            {
                //m_t[i].Suspend();
                m_tvThreads.Nodes[i].BackColor = Color.FromArgb(255, 192, 192);
                Application.DoEvents();
            }
        }

        public void Resume()
        {
            for (int i = 0; i < m_ThreadCount; i++)
            {
                //m_t[i].Resume();
                m_tvThreads.Nodes[i].BackColor = Color.FromArgb(192, 255, 192);
                Application.DoEvents();
            }
        }
    }
}